/**
 *
 * User: Zhikang.Peng
 * Date: 2018/06/20 17:28
 */
package references

import (
	"gitee.com/thghh/jvmgo/instructions/base"
	"gitee.com/thghh/jvmgo/rtda"
	"gitee.com/thghh/jvmgo/rtda/heap"
)

/**
创建指定类型和指定维度的多维数组（执行该指令时，操作栈中必须包含各维度的长度值），并将其引用值压入栈顶
index 指向运行时常量池中的数组类型的索引值
dimensions 几维数组
*/
type MULTI_ANEW_ARRAY struct {
	index      uint16
	dimensions uint8
}

func (self *MULTI_ANEW_ARRAY) FetchOperands(reader *base.BytecodeReader) {
	self.index = reader.ReadUint16()
	self.dimensions = reader.ReadUint8()
}

func (self *MULTI_ANEW_ARRAY) Execute(frame *rtda.Frame) {
	cp := frame.Method().Class().ConstantPool()
	classRef := cp.GetConstant(uint(self.index)).(*heap.ClassRef)
	arrayClass := classRef.ResolvedClass()
	stack := frame.OperandStack()
	counts := popAndCheckCounts(stack, int(self.dimensions))
	array := newMultiDimensionalArray(counts, arrayClass)
	stack.PushReference(array)
}

// 获取多维数组中每一维数组的长度
func popAndCheckCounts(stack *rtda.OperandStack, dimensions int) []int32 {
	// 操作数栈 „， count1， [count2， …] →栈顶
	counts := make([]int32, dimensions)
	for i := dimensions - 1; i >= 0; i-- {
		counts[i] = stack.PopInt()
		if counts[i] < 0 {
			panic("java.lang.NegativeArraySizeException")
		}
	}
	return counts
}

// 创建多维数组
func newMultiDimensionalArray(counts []int32, arrayClass *heap.Class) *heap.Object {
	// 数组长度
	count := uint(counts[0])
	array := arrayClass.NewArray(count)
	if len(counts) > 1 {
		refs := array.References()
		for i := range refs {
			refs[i] = newMultiDimensionalArray(counts[1:], arrayClass.ComponentClass())
		}
	}
	return array
}
